package csc.approximation;

import csc.main.Colors;
import java.io.Serializable;

/**
 * Represents equation of the form ax^2 + by^2 + cxy + dx + ey + f = 0.
 * Color pair is stored and can be obtained with getters.
 * @author Stanislau Dubrouski  
 */
public class AcaApproximationEquation implements ApproximationEquation, Serializable  {
    Colors colorFrom;
    Colors colorTo;
    
    private final double aParam;
    private final double bParam;
    private final double cParam;
    private final double dParam;
    private final double eParam;
    private final double fParam;

    /**
     *
     * @param colorFrom 1st color of color pair.
     * @param colorTo 2nd color from color pair.
     * @param aParam
     * @param bParam
     * @param cParam
     * @param dParam
     * @param eParam
     * @param fParam
     */
    public AcaApproximationEquation(Colors colorFrom, Colors colorTo, double aParam, double bParam, 
            double cParam, double dParam, 
            double eParam, double fParam) {
        this.colorFrom = colorFrom;
        this.colorTo = colorTo;
        this.aParam = aParam;
        this.bParam = bParam;
        this.cParam = cParam;
        this.dParam = dParam;
        this.eParam = eParam;
        this.fParam = fParam;
    }

    /**
     * Calculates estimated shift based on given x and y parameters.
     *
     * @param x
     * @param y
     * @return estimated shift for given coordinates.
     */  
    public float calculateEstimatedShiftValue(double x, double y){
        return (float) (aParam*x*x + bParam*y*y + cParam*x*y + dParam*x + eParam*y + fParam);
    }

    /**
     *
     * @return  1st vector from color pair
     */
    public Colors getColorFrom() {
        return colorFrom;
    }

    /**
     *
     * @return  2nd vector from color pair
     */
    public Colors getColorTo() {
        return colorTo;
    }

    /**
     *
     * @return String representation of equation
     */
    @Override
    public String toString() {
        return "AcaApproximationEquation{" + "colorFrom: " + this.colorFrom + ", colorTo: " + this.colorTo + ", aParam=" + aParam + ", bParam=" + bParam + ", cParam=" + cParam + ", dParam=" + dParam + ", eParam=" + eParam + ", fParam=" + fParam + '}';
    }   

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 23 * hash + (this.colorFrom != null ? this.colorFrom.hashCode() : 0);
        hash = 23 * hash + (this.colorTo != null ? this.colorTo.hashCode() : 0);
        hash = 23 * hash + (int) (Double.doubleToLongBits(this.aParam) ^ (Double.doubleToLongBits(this.aParam) >>> 32));
        hash = 23 * hash + (int) (Double.doubleToLongBits(this.bParam) ^ (Double.doubleToLongBits(this.bParam) >>> 32));
        hash = 23 * hash + (int) (Double.doubleToLongBits(this.cParam) ^ (Double.doubleToLongBits(this.cParam) >>> 32));
        hash = 23 * hash + (int) (Double.doubleToLongBits(this.dParam) ^ (Double.doubleToLongBits(this.dParam) >>> 32));
        hash = 23 * hash + (int) (Double.doubleToLongBits(this.eParam) ^ (Double.doubleToLongBits(this.eParam) >>> 32));
        hash = 23 * hash + (int) (Double.doubleToLongBits(this.fParam) ^ (Double.doubleToLongBits(this.fParam) >>> 32));
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final AcaApproximationEquation other = (AcaApproximationEquation) obj;
        if (this.colorFrom != other.colorFrom) {
            return false;
        }
        if (this.colorTo != other.colorTo) {
            return false;
        }
        if (Double.doubleToLongBits(this.aParam) != Double.doubleToLongBits(other.aParam)) {
            return false;
        }
        if (Double.doubleToLongBits(this.bParam) != Double.doubleToLongBits(other.bParam)) {
            return false;
        }
        if (Double.doubleToLongBits(this.cParam) != Double.doubleToLongBits(other.cParam)) {
            return false;
        }
        if (Double.doubleToLongBits(this.dParam) != Double.doubleToLongBits(other.dParam)) {
            return false;
        }
        if (Double.doubleToLongBits(this.eParam) != Double.doubleToLongBits(other.eParam)) {
            return false;
        }
        return true;
    }
    
    public boolean includesColor(Colors color) {
        if (color.equals(this.colorTo) || color.equals(this.colorFrom)){
            return true;
        }
        else return false;
    }
}
